"""
Git本地仓库处理模块

提供将数据库备份文件提交到本地Git仓库的功能，支持基本的Git操作。
现在使用新的模块化结构，将功能拆分为专门的子模块。
"""

import os
import shutil
from typing import Dict, List, Any, Optional
from pathlib import Path
import git
from git import Repo

# 导入新的模块化组件
from .operations import GitOperations
from .diff_checker import DiffChecker
from .backup_manager import create_git_backup_manager


class GitHandler:
    """Git本地仓库处理器
    
    用于管理数据库备份文件到本地Git仓库的提交操作。
    现在使用新的模块化组件来处理不同的功能。
    
    属性:
        repo (Repo): GitPython仓库对象
        logger (logging.Logger): 日志记录器
        git_ops (GitOperations): Git操作组件
        diff_checker (DiffChecker): 文件差异检查组件
        backup_manager (GitBackupManager): Git备份管理组件
    """
    
    def __init__(self, logger=None):
        """初始化Git处理器
        
        参数:
            logger: 日志记录器实例
                示例值: logging.getLogger(__name__)
        
        返回:
            GitHandler: Git处理器实例
        """
        self.logger = logger
        self.repo = None
        
        # 初始化新的模块化组件
        self.git_ops = GitOperations(logger)
        self.diff_checker = DiffChecker(logger)
        self.backup_manager = None  # 将在需要时初始化
    
    def _is_git_repository(self, path: str) -> bool:
        """检测指定路径是否处于Git仓库下
        
        参数:
            path (str): 要检测的路径
                示例值: "/path/to/check"
        
        返回:
            bool: 如果路径处于Git仓库下返回True，否则返回False
        """
        try:
            # 检查路径是否存在
            if not os.path.exists(path):
                return False
            
            # 检查路径本身是否是Git仓库
            if os.path.exists(os.path.join(path, '.git')):
                return True
            
            # 向上遍历父目录，检查是否处于Git仓库下
            current_path = os.path.abspath(path)
            while current_path != os.path.dirname(current_path):  # 直到根目录
                parent_path = os.path.dirname(current_path)
                if os.path.exists(os.path.join(parent_path, '.git')):
                    return True
                current_path = parent_path
            
            return False
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"检测Git仓库失败: {e}")
            return False
    
    def init_repository(self, local_path: str) -> Dict[str, Any]:
        """初始化本地Git仓库
        
        参数:
            local_path (str): 本地仓库路径
                示例值: "/path/to/backup-repo"
        
        返回:
            Dict[str, Any]: 初始化结果
                示例值: {
                    "success": True,
                    "local_path": "/path/to/backup-repo",
                    "initial_commit": True
                }
        """
        try:
            # 直接使用GitOperations组件初始化仓库
            result = self.git_ops.init_repository(local_path)
            
            if result["success"]:
                self.repo_path = local_path
                # 更新repo对象
                self.repo = Repo(local_path)
                
                if self.logger:
                    self.logger.info(f"Git仓库初始化成功: {local_path}")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"初始化Git仓库失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def check_file_differences(self, local_file: str, remote_file: str = None) -> Dict[str, Any]:
        """检查文件差异
        
        这个方法使用新的DiffChecker组件来检查本地文件与远程文件的差异。
        
        参数:
            local_file (str): 本地文件路径
                示例值: "/path/to/local/file.sql"
            remote_file (str): 远程文件路径，如果为None则使用本地文件名
                示例值: "/path/to/remote/file.sql"
        
        返回:
            Dict[str, Any]: 差异检查结果
                示例值: {
                    "success": True,
                    "different": True,
                    "local_size": 1024,
                    "remote_size": 512
                }
        """
        try:
            # 直接使用DiffChecker组件检查文件差异
            result = self.diff_checker.check_file_difference(
                file1_path=local_file,
                file2_path=remote_file
            )
            
            if self.logger:
                if result["different"]:
                    self.logger.info(f"文件存在差异: {local_file}")
                else:
                    self.logger.info(f"文件无差异: {local_file}")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"检查文件差异失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def add_files(self, file_patterns: List[str], 
                 commit_message: str = "Add backup files") -> Dict[str, Any]:
        """添加文件到Git暂存区并提交
        
        参数:
            file_patterns (List[str]): 文件模式列表
                示例值: ["backups/*.sql", "reports/*.html"]
            commit_message (str): 提交信息
                示例值: "添加数据库备份文件"
        
        返回:
            Dict[str, Any]: 添加和提交结果
                示例值: {
                    "success": True,
                    "files_added": 5,
                    "commit_hash": "a1b2c3d4e5f6",
                    "commit_message": "添加数据库备份文件"
                }
        """
        try:
            if not self.repo:
                return {"success": False, "error": "仓库未初始化"}
            
            # 使用GitOperations组件处理文件模式
            added_files = []
            for pattern in file_patterns:
                # 使用git add命令添加匹配的文件
                self.repo.git.add(pattern)
                
                # 获取添加的文件列表
                status = self.repo.git.status("--porcelain")
                for line in status.split('\n'):
                    if line.startswith('A ') or line.startswith('M '):
                        file_path = line[3:].strip()
                        if file_path not in added_files:
                            added_files.append(file_path)
            
            # 使用GitOperations组件提交更改
            if added_files:
                # 使用GitOperations组件进行提交
                commit_result = self.git_ops.commit_file(
                    repo_path=self.repo_path,
                    file_path=added_files[0],
                    commit_message=commit_message
                )
                
                if commit_result["success"]:
                    result = {
                        "success": True,
                        "files_added": len(added_files),
                        "commit_hash": commit_result.get("commit_hash", "")[:12],
                        "commit_message": commit_message,
                        "added_files": added_files
                    }
                    
                    if self.logger:
                        self.logger.info(f"提交 {len(added_files)} 个文件: {commit_message}")
                    
                    return result
                else:
                    return commit_result
            else:
                return {
                    "success": True,
                    "files_added": 0,
                    "message": "没有文件需要提交"
                }
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"添加文件失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def push_to_remote(self, remote_name: str = "origin", 
                      branch: str = "main", 
                      username: str = None, 
                      password: str = None) -> Dict[str, Any]:
        """推送更改到远程仓库
        
        参数:
            remote_name (str): 远程仓库名称
                示例值: "origin"
            branch (str): 分支名称
                示例值: "main"
            username (str): 用户名
                示例值: "username"
            password (str): 密码或访问令牌
                示例值: "your_token"
        
        返回:
            Dict[str, Any]: 推送结果
                示例值: {
                    "success": True,
                    "remote": "origin",
                    "branch": "main",
                    "pushed_commits": 3
                }
        """
        try:
            # 直接使用GitOperations组件推送到远程仓库
            result = self.git_ops.push_to_remote(
                repo_path=self.repo_path,
                remote_name=remote_name,
                branch=branch,
                username=username,
                password=password
            )
            
            if result["success"] and self.logger:
                self.logger.info(f"成功推送到远程仓库 {remote_name}/{branch}")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"推送失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def upload_backup_files(self, backup_files: List[str], 
                           repo_url: str, 
                           branch: str = "main",
                           username: str = None,
                           password: str = None,
                           commit_message: str = None) -> Dict[str, Any]:
        """上传备份文件到Git仓库
        
        这个方法使用新的GitBackupManager组件来处理备份文件的上传，
        包括文件差异检查、提交和推送。
        
        参数:
            backup_files (List[str]): 备份文件路径列表
                示例值: ["/path/to/backup1.sql", "/path/to/backup2.sql"]
            repo_url (str): 远程仓库URL
                示例值: "https://gitee.com/user/repo.git"
            branch (str): 分支名称
                示例值: "main"
            username (str): 用户名
                示例值: "username"
            password (str): 密码或访问令牌
                示例值: "your_token"
            commit_message (str): 提交消息，如果为None则使用默认消息
                示例值: "Upload backup files"
        
        返回:
            Dict[str, Any]: 上传结果
                示例值: {
                    "success": True,
                    "files_uploaded": 2,
                    "commit_hash": "a1b2c3d4e5f6"
                }
        """
        try:
            # 如果备份管理器未初始化，则创建它
            if not self.backup_manager:
                self.backup_manager = create_git_backup_manager(
                    local_repo_path=self.repo_path,
                    remote_repo_url=repo_url,
                    username=username,
                    password=password,
                    logger=self.logger
                )
            
            # 使用GitBackupManager组件处理备份文件
            result = self.backup_manager.process_backup_file(
                backup_file=backup_files[0] if backup_files else None,
                commit_message=commit_message
            )
            
            # 如果有多个文件，需要分别处理
            if len(backup_files) > 1:
                for backup_file in backup_files[1:]:
                    file_result = self.backup_manager.process_backup_file(
                        backup_file=backup_file,
                        commit_message=commit_message
                    )
                    if not file_result["success"]:
                        return file_result
            
            if result["success"] and self.logger:
                self.logger.info(f"成功上传 {len(backup_files)} 个备份文件")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"上传备份文件失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def pull_from_remote(self, remote_name: str = "origin", 
                       branch: str = "main",
                       username: str = None,
                       password: str = None) -> Dict[str, Any]:
        """从远程仓库拉取最新更改
        
        参数:
            remote_name (str): 远程仓库名称
                示例值: "origin"
            branch (str): 分支名称
                示例值: "main"
            username (str): 用户名
                示例值: "username"
            password (str): 密码或访问令牌
                示例值: "your_token"
        
        返回:
            Dict[str, Any]: 拉取结果
                示例值: {
                    "success": True,
                    "remote": "origin",
                    "branch": "main",
                    "updated_files": 5
                }
        """
        try:
            # 使用GitOperations组件从远程仓库拉取
            # 注意：当前GitOperations组件没有实现pull方法，所以我们需要直接使用GitPython
            if not self.repo:
                return {"success": False, "error": "仓库未初始化"}
            
            # 检查远程仓库是否存在
            if remote_name not in self.repo.remotes:
                return {"success": False, "error": f"远程仓库 {remote_name} 不存在"}
            
            remote = self.repo.remotes[remote_name]
            
            # 处理认证信息
            if username and password:
                original_url = remote.url
                try:
                    auth_url = self._add_auth_to_url(original_url, username, password)
                    remote.set_url(auth_url)
                    
                    # 执行拉取
                    pull_info = remote.pull(branch)
                    
                    # 恢复原始URL
                    remote.set_url(original_url)
                    
                except Exception as e:
                    remote.set_url(original_url)
                    raise e
            else:
                pull_info = remote.pull(branch)
            
            # 分析拉取结果
            updated_files = []
            for info in pull_info:
                if hasattr(info, 'flags') and info.flags & info.ERROR == 0:
                    # 获取更新的文件
                    if hasattr(info, 'commit') and info.commit:
                        # 这里简化处理，实际应该分析具体更改
                        updated_files.append(f"commit_{info.commit.hexsha[:12]}")
            
            result = {
                "success": True,
                "remote": remote_name,
                "branch": branch,
                "updated_files": len(updated_files)
            }
            
            if self.logger:
                self.logger.info(f"成功从 {remote_name}/{branch} 拉取更新")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"拉取失败: {e}")
            return {
                "success": False,
                "error": str(e)
            }
    
    def get_repository_info(self) -> Dict[str, Any]:
        """获取仓库信息
        
        这个方法使用新的GitOperations组件来获取仓库信息。
        
        返回:
            Dict[str, Any]: 仓库信息
                示例值: {
                    "local_path": "/tmp/backup-repo",
                    "branch": "main",
                    "commit_count": 15,
                    "last_commit": "a1b2c3d4e5f6",
                    "remotes": ["origin"]
                }
        """
        try:
            # 直接使用GitOperations组件获取仓库信息
            result = self.git_ops.get_repository_info(self.repo_path)
            
            if self.logger:
                self.logger.info("获取仓库信息成功")
            
            return result
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"获取仓库信息失败: {e}")
            return {"error": str(e)}
    
    def cleanup(self) -> bool:
        """清理资源
        
        这个方法使用新的GitOperations和GitBackupManager组件来清理资源。
        
        返回:
            bool: 清理是否成功
                示例值: True
        """
        try:
            # 清理GitOperations组件
            if self.git_ops:
                self.git_ops.cleanup()
            
            # 清理GitBackupManager组件
            if self.backup_manager:
                self.backup_manager.cleanup()
            
            # 清理当前GitHandler
            if self.repo and hasattr(self.repo, 'working_dir'):
                if hasattr(self.repo, 'close'):
                    self.repo.close()
                self.repo = None
            
            if self.logger:
                self.logger.info("Git处理器资源已清理")
            
            return True
            
        except Exception as e:
            if self.logger:
                self.logger.error(f"清理资源失败: {e}")
            return False
    
    def _add_auth_to_url(self, url: str, username: str, password: str) -> str:
        """在URL中添加认证信息
        
        参数:
            url (str): 原始URL
                示例值: "https://gitee.com/username/repo.git"
            username (str): 用户名
                示例值: "username"
            password (str): 密码
                示例值: "password"
        
        返回:
            str: 包含认证信息的URL
                示例值: "https://username:password@gitee.com/username/repo.git"
        """
        if "@" in url:
            # 如果URL已经包含认证信息，替换它
            protocol_part = url.split("://")[0]
            repo_path = url.split("@")[-1]
            return f"{protocol_part}://{username}:{password}@{repo_path}"
        else:
            # 添加认证信息
            return url.replace("://", f"://{username}:{password}@")
    
    def _create_initial_commit(self) -> None:
        """创建初始提交
        
        返回:
            None
        """
        try:
            # 创建README文件
            readme_content = """# 数据库备份仓库

这个仓库用于存储数据库备份文件。

## 文件结构
- `backups/`: 备份文件目录
- `reports/`: 差异报告目录

## 使用说明
备份文件会自动上传到此仓库进行版本管理。
"""
            
            readme_path = os.path.join(self.repo.working_dir, "README.md")
            with open(readme_path, 'w', encoding='utf-8') as f:
                f.write(readme_content)
            
            # 创建目录结构
            os.makedirs(os.path.join(self.repo.working_dir, "backups"), exist_ok=True)
            os.makedirs(os.path.join(self.repo.working_dir, "reports"), exist_ok=True)
            
            # 添加.gitignore文件
            gitignore_content = """# 临时文件
*.tmp
*.temp

# 日志文件
*.log

# 系统文件
.DS_Store
Thumbs.db

# 备份文件（保留SQL文件）
# !*.sql
"""
            gitignore_path = os.path.join(self.repo.working_dir, ".gitignore")
            with open(gitignore_path, 'w', encoding='utf-8') as f:
                f.write(gitignore_content)
            
            # 添加文件并提交
            self.repo.git.add("README.md")
            self.repo.git.add(".gitignore")
            self.repo.git.add("backups/")
            self.repo.git.add("reports/")
            
            self.repo.index.commit("Initial commit: Add repository structure")
            
            if self.logger:
                self.logger.info("创建初始提交完成")
                
        except Exception as e:
            if self.logger:
                self.logger.error(f"创建初始提交失败: {e}")
            raise